package com.le.tester.book.concurrentjavafight.l7_2_5;

import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * createTime：2022/11/21 11:11
 * description：使用tasksExecutor来保存未完成的任务，并且可以进行后续的执行
 * 考虑幂等性的严格要求
 */
public abstract class WebCrawler {
    //可见性
    private volatile TracingExecutor executor;

    private final Set<URL> urlsToCrawl = new HashSet<>();

    private static final Long TIMEOUT = 100L;

    private static final TimeUnit UNIT = TimeUnit.MILLISECONDS;

    public synchronized void start() {
        executor = new TracingExecutor(Executors.newCachedThreadPool());

        for (URL url : urlsToCrawl) {
            submitCrawlTask(url);
        }

        //清空了set<List>
        urlsToCrawl.clear();
    }

    public synchronized void stop() throws InterruptedException {
        //保存想要停止的task
        try {
            saveUnCrawled(executor.shutdownNow());
            if (executor.awaitTermination(TIMEOUT, UNIT)) {
                saveUnCrawled(executor.getCanceledTasks());
            }
        } finally {
            executor = null;
        }

    }

    //保存取消爬虫List
    private void saveUnCrawled(List<Runnable> unCrawled) {
        for (Runnable task : unCrawled) {

            urlsToCrawl.add(((CrawlTask) task).getPage());
        }
    }

    protected abstract List<URL> processPage(URL url);

    private void submitCrawlTask(URL u) {
        executor.execute(new CrawlTask(u));
    }

    private class CrawlTask implements Runnable {

        private final URL url;

        private CrawlTask(URL url) {
            this.url = url;
        }

        @Override
        public void run() {
            for (URL link : processPage(url)) {
                if (Thread.currentThread().isInterrupted())
                    return;
                submitCrawlTask(link);
            }
        }

        public URL getPage() {
            return url;
        }

    }
}
